iT邦幫忙

2022 iThome 鐵人賽

DAY 25
1
Modern Web

自己做一個價值幾十萬的動態網站,學會Mern開發、前台UI設計各式觀念與各式Lib、typescript你該學會的前端技術系列 第 25

「全端挑戰」Mui與framerMotion特效介紹,創建新model,Order訂房下單Api與CheckBox函數紀錄表單useState

  • 分享至 

  • xImage
  •  

鐵人賽 Day25自己做一個價值幾十萬的動態網站

第二十五課:收尾與創建order訂單完成訂房手續 part1

訂房操作限制,防呆機制需查詢時間才能觀看更多房間資訊

應該要先設定好時間才能讓他訂房,如果沒有讓先定好時間不會顯示這些資訊

並這些設定都可以客製化製作在如沒有選擇住宿時間,中間區塊其實是無法顯示剩幾間房,當這種情況發生時,可以顯示如自己本身飯店的介紹等等的,等選擇完時間後才會顯示出剩幾間房等條件資料操作。所以這邊示範如何利用@mui/material的一些特效讓網站的品質提升。

Mui與framerMotion特效介紹,操作禁止與彈出特效,增加操作互動性



下列分別是Mui與framerMotion的官方連結,裡面提供很多精美的特效可以使用
https://mui.com/zh/material-ui/react-tooltip/
https://www.framer.com/motion/
所以首先我們先來搞定讓使用者必須先查詢日期才能看到更詳細飯店資訊的設置,

npm install @mui/material @emotion/react @emotion/styled

{DatesLength == 0 ?
    <ItemTooltip title="請先輸入住宿日期,並按左側 搜尋 查看結果" followCursor>
      <button className='btn' >查看客房供應情況</button>
    </ItemTooltip>
    :
    <Link to={`/hotels/${dataDetail._id}`}>
      <button className='btn' >查看客房供應情況</button>
    </Link>
}



上面處理完一些細節後,我們要來直接新增一個order Model來處理我們的訂房訂單,也是最後一個全流程的練習,讓自己可以更完整的了解,並感知到nosql類的強大,可以不斷且快速的擴展新的資料型態與資料庫,當有需求時,就可以一條龍的完成。

設立新的model,Order訂房下單準備與後台之間得串接

所以為了讓我們的Reservation component可以在最後幫我們做一個結尾,在按下確定訂房的按鈕後,建立一筆我們的order訂單,同時新增我們的room的unavailableDates的時間,訂單是為了後台管理知道誰訂了單跟管理查核對帳單,後面的unavailableDates是為了處理我們UI上的checkBox,如果當unavailableDates與我們在前端最後context所選的date有衝突,我們將會讓checkBox不能被勾選,代表已經被人訂走了,所以為了完成這兩件事,我們可以先來處理,order model的建立,並快速複習與建置關於Order訂單的CRUD,回到我們的Api folder中的model內。

import mongoose from 'mongoose';
const OrderSchema = new mongoose.Schema({
        userId:{type:String, required:true}, //紀錄誰下這個訂單的
        hotelId:{type:String, required:true}, //紀錄這個訂單的飯店編號
        RoomNumberId: //一次紀錄一個訂房的房間,但可以一次下訂許多的房間
           [{//紀錄這個訂單的房間編號
                    type:String, required:true
            }
           ],
        ReservationDates:[{
            startDate:{type:Date,required:true},
            endDate:{type:Date,required:true}
        }],
        totalPrice:{type:Number, required:true},//總共下訂金額
        status:{type:String, default:"待確認訂單"},//這個是給後台看得狀態讓之後訂單好管理
        options:[{ //條件設置就紀錄我們的人數條件
            adult:{type:Number, default:1},
            children:{type:Number, default:0},
            rooms:{type:Number, default:1},
        }]
    },{timestamps:true} 
)
export default mongoose.model("Order",OrderSchema)

這邊我們的order model會要包含使用者id、飯店/房間id、住宿的時間區間、總價格與人數,這邊選擇將飯店、房間編號id都紀錄進去,當然也可以只記房間編號id,並後台如果需要觀看可以在往上回朔查詢母資料hotelid 與roomId,但為了方便我們就選擇一次紀錄,在後台上如果需要顯示,就可以一次叫出來資料id來觀看飯店資料等資訊。
並處理我們的app.get所延伸的ApiRoutes與routesController

import orderApiRoute from "./ApiRoutes/order.js"
//要放在app.use(express.json())順序也會影響所以不能亂排
app.use("/api/v1/order",orderApiRoute) 


ApiRoute中的order.js,並這邊只要是import都要記得打上.js,因為前面有提到跟react不同,

import express from "express"
import { createOrder, deleteOrder, getAllOrders, getOrder, updatedOrder } from "../RoutesController/order.js"
//這邊前面的url是/api/v1/Order
const router = express.Router()
//創建第一筆order資料
router.post("/",createOrder)
//抓取第一筆order資料練習
router.get("/find/:id",getOrder)
//將第一筆order資料做修改練習
router.put("/:id",updatedOrder)
//刪除order資料
router.delete("/:id",deleteOrder)
//抓取所有order資料
router.get("/",getAllOrders)
export default router

RoutesController的內容連結
並完成後可以先去insomnia中做測試,看是否能完整的新增order訂單與輸入的資料型態也可以先做測試。

insomnia的Order Api測試

{
	"userId": "63272ee2b87dbcab2d8e7401",
	"hotelId": "6316b9f6d4297b219327842e",
	"RoomNumberId": [
			"6332c8d2a9e61930497ae156"
	],
	"ReservationDates":[
		{
  "startDate": "2022-09-28T16:00:00.000Z",
	"endDate": "2022-09-29T16:00:00.000Z"
    }
	],
	"totalPrice":0,
	"options":[
		{"adult":1,"children":1,"rooms":1}	
    ]
}

這邊測資可以換上自己資料庫的真實id作測試,當作UI到時候傳過來的資料預覽。並完成這只五隻的測試包括丟入order訂單id修改查看等等的


這邊測試Api完成能運行後我們就可以快速回到我們的前台UI。

使用axios回到前台UI做串接

如同我們在registerPage所製作的一樣,我們可以先測試使否能上傳我們得訂單資料,確定OK後,再一起將room資料庫中roomNumber新增unavailableDates的時間區間一同上傳。所以這邊的handleClick也要處理兩件事情。


const { date, options } = useContext(OptionsContext)
const { user } = useContext(LoginContext)
//在這邊建立我們的order訂單,同時新增我們的room的unavailableDates的時間
//並之後在爬梳unavailableDates如果發現有客戶有選的時間跟我們的unavailableDates有衝突就不讓他勾選
const [roomNumber, setRoomNumber] = useState([])
const [orderData, setOrderData] = useState({
    userId: user._id,
    hotelId: hotelid,
    RoomNumberId: [],
    ReservationDates: [
        {
            startDate: date[0].startDate,
            endDate: date[0].endDate,
        }
    ],
    totalPrice: 0,
    options: {
        adult: options.adult,
        children: options.children,
        rooms: options.room,
    }
})

CheckBox函數製作,紀錄RoomNumber useState

那這邊我們要先來處理handleCheckBox,來紀錄我們的房型編號,如果依照之前的概念製作如下。


所以我們要同時解決兩個問題,checkBox的打勾取消與不重複紀錄,所以我們可以利用input checkBox的特性,當checkBox是被打勾的是checked=true,那相反的取消打勾就是checked=false,那當checked=false之時,我們用filter把之前紀錄的roomNumber給刪除掉,所以先創立handleCheckBox來處理這個條件子句。

const handleCheckBox = (e) => {
    const roomNumberId = e.target.value
    const checked = e.target.checked
    //這邊特別要製作把打勾的再取消掉,所以用到checked與filter來排除
    setRoomNumber(
        checked
            ? [...roomNumber, roomNumberId] //打勾存入
            : roomNumber.filter((item) => item !== roomNumberId) //取消打勾的id刪除
    );
}

這邊是示範了可以再State裡面也用 ?: 條件來做到我們想要完成的勾選任務
完成後應該長下列樣子。

結論

挑戰快進入到尾聲,練習到發現越來越熟能生巧,從model到Api到設置controller函數到後面UI的各種axios與動畫應用,基本的CRUD概念都可以不斷延續,而到後期會發現更多更難的資料應用都必須在後端Api上開始下一些苦工,所以當我們前端越來越熟練以後,可以開始來針對不同的資料去將我們的動態網站進行更一步的優化,如使用到推薦系統等等的,但如果資料數量還沒那麼多後端可以先針對特定資料去做整理與爬梳即可,像訂房網這邊如果要繼續優化,除了導入現金流,接下來也可以試著嘗試自動導入各種飯店資料來進行介紹營運,但如人力不足的情況下,要新增上百筆的資料,這部分也可以寫爬梳加上自動化automation來串接Api,上傳想要的資料,或是針對我們的前端coding去做RWD整理與優化,會發現越來越多的細節想完成,雖然每一次都是挑戰都會遇到卡點,但只要想到在這過程中,自己突破了就是不斷的在變強,且如果完成這種動態網站後,如自身又對行銷很拿手,加強自身的跨領域的軟體硬實力與行銷軟實力,以自學到現在的我,體會是充實且充滿挑戰的。


上一篇
「全端挑戰」useLocation.pathname應用,optionsContext資料同步更新、空房情況UI設計與串接room顯示資料
下一篇
「全端挑戰」useState的re-render執行時間與useEffect配合、new Date與getTime的宣告
系列文
自己做一個價值幾十萬的動態網站,學會Mern開發、前台UI設計各式觀念與各式Lib、typescript你該學會的前端技術30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言